﻿using System;
using System.IO;

namespace yacomp.os
{
    using yacomp.helpers;
    using yacomp.structs;
    public class YacompFile : IDisposable
    {
        internal struct_yacomp_file info;
        internal YacompStorage ref_storage { get; set; }

        public string FileName;
        public string FullPath;
        public string FileExtension;
        public DateTime EditTime { get { return info.time_edit; } }
        public uint Crc32 { get { return info.crc32; } }
        public uint FileSize { get { return info.not_compress_size; } }
        public string ID { get { return info.id; } }
        internal bool leave_open;
        internal YacompFile(struct_yacomp_file f, YacompStorage storage, bool leave_open = false)
        {
            info = f;
            ref_storage = storage;
            this.leave_open = leave_open;
            update_by_info();
        }
        internal YacompFile CopyTo(YacompStorage storage)
        {
            return new YacompFile(info, storage);
        }
        internal void update_by_info()
        {
            FileName = helper.read_filename(info.filename);
            FileExtension = helper.read_file_extension(info.filename);
            FullPath = helper.to_standard_path(info.filename);
            if (FullPath[0] == helper.path_split_02) FullPath = FullPath.Substring(1);

            info.filepath_bytes = helper.take_utf8_bytes(FullPath);
            info.filepath_bytes_size = (ushort)info.filepath_bytes.Length;
        }
        public Stream ToStream()
        {
            if (info.compress_tag)
            {
                var mem = new MemoryStream();
                ToStream(mem, true);
                mem.Seek(0, SeekOrigin.Begin);
                return mem;
            }

            if (string.IsNullOrEmpty(info.fullpath_localos) || !File.Exists(info.fullpath_localos))
            {
                info.not_compress_mem.Seek(0, SeekOrigin.Begin);
                return info.not_compress_mem;
            }

            return File.Open(info.fullpath_localos, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
        }
        public void ToStream(Stream dst, bool not_despose = false)
        {
            if (info.compress_tag)
                if (not_despose) info.algo.decompress(this, dst);
                else using (dst) info.algo.decompress(this, dst);
        }
        public void Compress(Stream dst, bool not_despose = false)
        {
            if (not_despose) info.compress_size = info.algo.compress(this, dst);
            else using (dst) info.compress_size = info.algo.compress(this, dst);
        }
        public void Rename(string name)
        {
            ref_storage.file_map.Remove(ID);
            var parentPath = ParentPath();
            parentPath.files.Remove(ID);

            info.filename = helper.to_absolute_path(name, ref_storage.now_path);
            info.id = ref_storage.calc_id(info.filename);
            parentPath.files.Add(ID);
            ref_storage.file_map.Add(ID, this);
            update_by_info();
        }
        public YacompPath ParentPath()
        {
            var path = helper.read_pathname(this.FullPath);
            return ref_storage.FindPath(path);
        }
        public void Delete()
        {
            ref_storage.RemoveFile(this.FullPath);
        }

        public void Dispose()
        {
            this.Delete();
            if (!leave_open && this.info.not_compress_mem != null) this.info.not_compress_mem.Dispose();
            if (!leave_open && this.info.compress_mem != null) this.info.compress_mem.Dispose();
            this.info.not_compress_mem = null;
            this.info.compress_mem = null;
        }
    }
}
